#pragma once
#include <iostream>
#include <memory>
#include "Socket.hpp"
#include <sys/epoll.h>

using namespace std;

class EpollSever
{
    const static int N = 64;

public:
    EpollSever(uint16_t port)
        : _port(port), _listensock(make_unique<TcpSocket>())
    {
        InetAddr addr("0", port);
        _listensock->BuildListenSocket(addr);
        _efds = epoll_create(128);
        // 先把listensock加入红黑树
        struct epoll_event et;
        et.events = EPOLLIN;
        et.data.fd = _listensock->sockfd();
        int n = epoll_ctl(_efds, EPOLL_CTL_ADD, _listensock->sockfd(), &et);
        if (n < 0)
        {
            LOG(ERROR, "epoll_ctl listen fail: %s\n", strerror(errno));
            return;
        }
    }
    void HandlerTask(int n)
    {
        for (int i = 0; i < n; i++)
        {
            // 区分
            uint32_t event = _evt[i].events;
            int sockfd = _evt[i].data.fd;

            // 读事件
            if (event & EPOLLIN)
            {
                // listenfd行为
                if (sockfd == _listensock->sockfd())
                {
                    InetAddr client;
                    int fd = _listensock->AcceptSocket(&client);
                    if (fd < 0)
                        continue;
                    struct epoll_event et;
                    et.events = EPOLLIN;
                    et.data.fd = fd;
                    int n = epoll_ctl(_efds, EPOLL_CTL_ADD, fd, &et);
                    if (n < 0)
                    {
                        LOG(ERROR, "epoll_ctl normalfd fail: %s\n", strerror(errno));
                        return;
                    }
                    LOG(INFO, "listenfd ready, new fd: %d\n", fd);
                }
                // 普通fd行为
                else
                {
                    char buffer[1024];
                    //有坑，因为没有协议，所以recv读不全！！！！！！！！！！
                    ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
                    if (n == 0)
                    {
                        // 要删除的fd，必须合法，所以要放前面！！！
                        epoll_ctl(_efds, EPOLL_CTL_DEL, sockfd, nullptr);
                        close(sockfd);
                        LOG(DEBUG, "recv end,close fd: %d\n", sockfd);
                    }
                    else if (n < 0)
                    {
                        // 要删除的fd，必须合法，所以要放前面！！！
                        epoll_ctl(_efds, EPOLL_CTL_DEL, sockfd, nullptr);
                        close(sockfd);
                        LOG(DEBUG, "recv fail,close fd: %d\n", sockfd);
                    }
                    else
                    {
                        LOG(INFO, "recv begin, new fd: %d\n", sockfd);
                        buffer[n] = 0;
                        cout << "client say# " << buffer << endl;
                        string severecho = buffer;
                        severecho += " ";
                        send(sockfd, severecho.c_str(), severecho.size(), 0);
                    }
                }
            }
        }
    }
    void Loop()
    {
        while (1)
        {
            int timeout = 3000;
            int n = epoll_wait(_efds, _evt, N, timeout);
            switch (n)
            {
            case 0:
                LOG(WARNING, "epoll_wait overtime\n");
                break;
            case -1:
                LOG(ERROR, "epoll_wait fail: %s\n", strerror(errno));
                break;
            default:
                LOG(INFO, "epoll_wait success n: %d\n", n);
                HandlerTask(n);
                break;
            }
        }
    }
    ~EpollSever()
    {
        close(_listensock->sockfd());
        if (_efds >= 0)
            close(_efds);
    }

private:
    uint16_t _port;
    unique_ptr<Socket> _listensock;
    int _efds;
    struct epoll_event _evt[N];
};